package com.jack.xiaoer.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import com.jack.xiaoer.constant.AccountStateEnum;
import com.jack.xiaoer.constant.AccountTypeEnum;
import com.jack.xiaoer.dao.UserMapper;
import com.jack.xiaoer.dto.AccountDTO;
import com.jack.xiaoer.entity.User;
import com.jack.xiaoer.service.AccountService;
import com.jack.xiaoer.service.error.AccountExistedException;
import com.jack.xiaoer.service.error.AccountLockedException;
import com.jack.xiaoer.util.EncryptUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * Created by Jackaroo Zhang on 2018/12/8.
 */
@Service
public class AccountServiceImpl implements AccountService {

    private final Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Override
    public AccountDTO getAccount(Optional<AccountDTO> accountDTO) {
        if (!accountDTO.isPresent()) return null;

        final AccountDTO accDTO = accountDTO.get();

        switch (accDTO.getLoginType()) {
            case COMMON:
                return getAccountByCommon(accDTO);
            default:
                return null;
        }
    }

    @Override
    public AccountDTO createAccount(Optional<AccountDTO> accountDTO) {
        if (!accountDTO.isPresent()) {
            return null;
        }

        final AccountDTO accDTO = accountDTO.get();

        if (accountExisted(accountDTO)) {
            throw new AccountExistedException("account have existed");
        }

        accDTO.setPassword(EncryptUtil.md5(accDTO.getPassword()));

        User user = new User();
        BeanUtils.copyProperties(accDTO, user);
        user.setState(AccountStateEnum.NORMAL);
        user.setAccountType(AccountTypeEnum.COMMON);
        user.setGmtCreate(Instant.now());
        user.setGmtModified(Instant.now());

        int row = userMapper.insert(user);
        if (row < 1) {
            return null;
        }

        AccountDTO retDTO = new AccountDTO();
        BeanUtils.copyProperties(user, retDTO, "password");
        return retDTO;
    }

    @Override
    public boolean accountExisted(Optional<AccountDTO> accountDTO) {
        if (!accountDTO.isPresent()) {
            return false;
        }

        final AccountDTO accDTO = accountDTO.get();

        HashMap<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("username", accDTO.getUsername());
        List<User> users = userMapper.selectByMap(queryMap);
        if (users != null && !users.isEmpty()) {
            return true;
        }

        return false;
    }


    private AccountDTO getAccountByCommon(AccountDTO accDTO) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", accDTO.getUsername());
        queryWrapper.eq("password", EncryptUtil.md5(accDTO.getPassword()));

        List<User> users = userMapper.selectList(queryWrapper);

        if (null == users || users.isEmpty()) {
            return null;
        }
        if (users.size() > 1) {
            logger.error("there are more than one record that use the same username[{}]!", accDTO.getUsername());
            return null;
        }
        final User user = users.get(0);
        if (user.getState() == AccountStateEnum.LOCKED) {
            logger.info("account have been locked!");
            throw new AccountLockedException();
        }
        if (user.getState() == AccountStateEnum.DELETED) {
            return null;
        }

        AccountDTO retAccountDTO = new AccountDTO();
        BeanUtils.copyProperties(user, retAccountDTO, "password");

        return retAccountDTO;
    }

}
